/**************************************************************************//**
 * @item     CosyOS Kernel
 * @file     usv_loc.c
 * @brief    Service for User Task is to be executed locally
 * @author   迟凯峰
 * @version  V2.3.4
 * @date     2023.05.13
 ******************************************************************************/

#include "glovar.h"
#include "sysapi.h"
#include "svs.h"

bool __enter_critical(void)
{
	mEnterCritical;
	return true;
}

tECODE __start_task(tspTaskHandle task_hand, u8 state)
{
	static tTID tid = 0;
	if(!task_hand->TID)
	{
		tid++;
		task_hand->TID = tid;
	}
	#if SYSCFG_TASKCREATEMODE == __STATIC__ || SYSCFG_TASKCREATEMODE == __BALANCE__
	task_hand->state = state;
	#elif SYSCFG_TASKCREATEMODE == __DYNAMIC__
	task_hand->task_node = (tspTaskNode)state;
	#endif
	vACTBUF = task_hand;
	vScheduling_f = true;
	mPSV_Trigger;
	mExitCritical;
	OS_NOPxX;
	if(vRET_f) return vACTRET;
	else return (tECODE)vTASKING->blocktype;
}

tECODE __resume_task(tspTaskNode task_node)
{
	#if SYSCFG_TASKCREATEMODE == __DYNAMIC__
	if(task_node == NULL)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	#endif
	if(task_node->state & __SUSPENDED__)
	{
		task_node->state &= __RESUME__;
		if(task_node->state <= __FLOATING__ && task_node->TPL > vTASKING->TPL)
		{
			vScheduling_f = true;
			mPSV_Trigger;
		}
		mExitCritical;
		return ECODE_NOERR;
	}
	else if(task_node->state < __STOPPED__)
	{
		mExitCritical;
		return ECODE_TASKUNSUSPENDED;
	}
	else if(task_node->state & __STOPPED__)
	{
		mExitCritical;
		return ECODE_TASKSTOPPED;
	}
	else if(task_node->state == __DELETED__)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	else
	{
		mExitCritical;
		return ECODE_DONOTKNOW;
	}
}

tECODE __suspend_task(tspTaskNode task_node)
{
	#if SYSCFG_TASKCREATEMODE == __DYNAMIC__
	if(task_node == NULL)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	#endif
	if(task_node->state < __SUSPENDED__)
	{
		task_node->state |= __SUSPENDED__;
		if(task_node == vTASKING)
		{
			vScheduling_f = true;
			mPSV_Trigger;
		}
		mExitCritical;
		return ECODE_NOERR;
	}
	else if(task_node->state & __SUSPENDED__)
	{
		mExitCritical;
		return ECODE_TASKSUSPENDED;
	}
	else if(task_node->state & __STOPPED__)
	{
		mExitCritical;
		return ECODE_TASKSTOPPED;
	}
	else if(task_node->state == __DELETED__)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	else
	{
		mExitCritical;
		return ECODE_DONOTKNOW;
	}
}

tECODE __delete_task(tspTaskNode task_node)
{
	#if SYSCFG_TASKCREATEMODE == __DYNAMIC__
	if(task_node == NULL)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	#endif
	if(task_node->state < __DELETED__)
	{
		task_node->state = __DELETED__;
		if(task_node == vTASKING)
		{
			vScheduling_f = true;
			mPSV_Trigger;
		}
		mExitCritical;
		return ECODE_NOERR;
	}
	else if(task_node->state == __DELETED__)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	else
	{
		mExitCritical;
		return ECODE_DONOTKNOW;
	}
}

tECODE __ressus_task(tspTaskNode task_node)
{
	#if SYSCFG_TASKCREATEMODE == __DYNAMIC__
	if(task_node == NULL)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	#endif
	if(task_node->state & __SUSPENDED__)
	{
		task_node->state &= __RESUME__;
	}
	else if(task_node->state < __STOPPED__)
	{
		mExitCritical;
		return ECODE_TASKUNSUSPENDED;
	}
	else if(task_node->state & __STOPPED__)
	{
		mExitCritical;
		return ECODE_TASKSTOPPED;
	}
	else if(task_node->state == __DELETED__)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	else
	{
		mExitCritical;
		return ECODE_DONOTKNOW;
	}
	vTASKING->state |= __SUSPENDED__;
	vScheduling_f = true;
	mPSV_Trigger;
	mExitCritical;
	return ECODE_NOERR;
}

tECODE __set_priority(tspTaskNode task_node, u8 tpl)
{
	mEntry_Monitor;
	#if SYSCFG_TASKCREATEMODE == __DYNAMIC__
	if(task_node == NULL)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	#endif
	if(task_node->state < __STOPPED__)
	{
		if(task_node->TPL != tpl)
		{
			task_node->TPL = tpl;
			sSetPriority(task_node);
			if(tpl > vTASKING->TPL && task_node->state <= __FLOATING__)
			{
				vScheduling_f = true;
				mPSV_Trigger;
			}
			mExitCritical;
			return ECODE_NOERR;
		}
		else
		{
			mExitCritical;
			return ECODE_TPLUNCHANGED;
		}
	}
	else if(task_node->state & __STOPPED__)
	{
		mExitCritical;
		return ECODE_TASKSTOPPED;
	}
	else if(task_node->state == __DELETED__)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	else
	{
		mExitCritical;
		return ECODE_DONOTKNOW;
	}
}

void __delay(tDelay tc)
{
	if(tc)
	{
		vDELAY_STMR[vTASKING->TID] = tc;
		vTASKING->blocktype = __DELAY__;
		vTASKING->state = __BLOCKED__;
	}
	vScheduling_f = true;
	mPSV_Trigger;
	mExitCritical;
}

void __free_mut(tspMut p)
{
	mEntry_Monitor;
	if(vTASKING == p->node)
	{
		p->mut = true;
		if(vTASKING->TPL > p->TPL)
		{
			vTASKING->TPL = p->TPL;
			sSetPriority(vTASKING);
			vScheduling_f = true;
			mPSV_Trigger;
		}
	}
	mExitCritical;
}

bool __take_mut(tspMut p, tDelay tc)
{
	mEntry_Monitor;
	if(p->mut)
	{
		p->mut = false;
		p->node = vTASKING;
		p->TPL = vTASKING->TPL;
		p->tpl = vTASKING->TPL;
		mExitCritical;
		return true;
	}
	else if(tc)
	{
		vDELAY_STMR[vTASKING->TID] = tc;
		vTASKING->blocktype = ~tc ? __MUTEX__ | __DELAY__ : __MUTEX__;
		vTASKING->state = __BLOCKED__;
		vTASKING->ptr = p;
		if(vTASKING->TPL > p->tpl)
		{
			p->tpl = vTASKING->TPL;
			p->node->TPL = vTASKING->TPL;
			sSetPriority(p->node);
		}
		vScheduling_f = true;
		mPSV_Trigger;
		mExitCritical;
		OS_NOPxX;
		return (bool)vTASKING->blocktype;
	}
	else
	{
		mExitCritical;
		return false;
	}
}

bool __take_bin(volatile bool *p, tDelay tc, u8 type)
{
	mEntry_Monitor;
	if(*p)
	{
		if(type == __BINARY_TAKE__)
		{
			*p = false;
		}
		mExitCritical;
		return true;
	}
	else if(tc)
	{
		vDELAY_STMR[vTASKING->TID] = tc;
		vTASKING->blocktype = ~tc ? type | __DELAY__ : type;
		vTASKING->state = __BLOCKED__;
		vTASKING->ptr = (void *)p;
		vScheduling_f = true;
		mPSV_Trigger;
		mExitCritical;
		OS_NOPxX;
		return (bool)vTASKING->blocktype;
	}
	else
	{
		mExitCritical;
		return false;
	}
}

bool __take_sem(tspSem p, tDelay tc)
{
	mEntry_Monitor;
	if(p->counter)
	{
		p->counter--;
		mExitCritical;
		return true;
	}
	else if(tc)
	{
		vDELAY_STMR[vTASKING->TID] = tc;
		vTASKING->blocktype = ~tc ? __SEMAPHORE__ | __DELAY__ : __SEMAPHORE__;
		vTASKING->state = __BLOCKED__;
		vTASKING->ptr = p;
		vScheduling_f = true;
		mPSV_Trigger;
		mExitCritical;
		OS_NOPxX;
		return (bool)vTASKING->blocktype;
	}
	else
	{
		mExitCritical;
		return false;
	}
}

#if SYSCFG_DIRMSG == __ENABLED__

bool __recv_dm(tDM *m0_, tDM *m1, size_t size, tDelay tc) __REENTRANT__
{
	mEntry_Monitor;
	if(*m0_);
	else if(tc)
	{
		vDELAY_STMR[vTASKING->TID] = tc;
		vTASKING->blocktype = ~tc ? __RECV_DM__ | __DELAY__ : __RECV_DM__;
		vTASKING->state = __BLOCKED__;
		vTASKING->ptr = (void *)m0_;
		vScheduling_f = true;
		mPSV_Trigger;
		mExitCritical;
		OS_NOPxX;
		if(vTASKING->blocktype)
		{
			mEnterCritical;
		}
		else
		{
			return false;
		}
	}
	else
	{
		mExitCritical;
		return false;
	}
	*m0_ = false;
	do{
		*m1++ = *++m0_;
	}while(--size);
	mExitCritical;
	return true;
}

#endif

#if SYSCFG_MAILBOX == __ENABLED__

bool __recv_mail(void *lm, void *gm, size_t size, volatile bool *gf, tDelay tc) __REENTRANT__
{
	mEntry_Monitor;
	if(*gf) goto Lable;
	else if(tc)
	{
		vDELAY_STMR[vTASKING->TID] = tc;
		vTASKING->blocktype = ~tc ? __RECV_MAIL__ | __DELAY__ : __RECV_MAIL__;
		vTASKING->state = __BLOCKED__;
		vTASKING->ptr = (void *)gf;
		vScheduling_f = true;
		mPSV_Trigger;
		mExitCritical;
		OS_NOPxX;
		mEnterCritical;
		if(*gf) goto Lable;
	}
	mExitCritical;
	return false;
	Lable:
	__memcpy(lm, gm, size);
	*gf = false;
	mExitCritical;
	return true;
}

#endif

#if SYSCFG_MSGQUEUE == __ENABLED__

void *__recv_msg(tspMsgQueue msg_queue, tDelay tc)
{
	tspMsgNode msg_node;
	mEntry_Monitor;
	msg_queue->mutex = false;
	if(!msg_queue->counter)
	{
		goto Lable;
	}
	if(msg_queue->type == __DYNAMIC__)
	{
		sRecvMsg_Dynamic(vTASKING->ptr);
	}
	else
	{
		sRecvMsg_Static(vTASKING->ptr);
	}
	msg_queue->mutex = true;
	mExitCritical;
	return vTASKING->ptr;
	Lable:
	msg_queue->mutex = true;
	if(tc)
	{
		vDELAY_STMR[vTASKING->TID] = tc;
		vTASKING->blocktype = ~tc ? __RECV_MSG__ | __DELAY__ : __RECV_MSG__;
		vTASKING->state = __BLOCKED__;
		vTASKING->ptr = (void *)msg_queue;
		vScheduling_f = true;
		mPSV_Trigger;
		mExitCritical;
		OS_NOPxX;
		return vTASKING->ptr;
	}
	else
	{
		mExitCritical;
		return NULL;
	}
}

tECODE __send_msg(tspMsgQueue msg_queue, void *msg)
{
	mEntry_Monitor;
	msg_queue->mutex = false;
	if(msg_queue->counter == msg_queue->len)
	{
		msg_queue->mutex = true;
		vAlarm.overflow_msgqueue = true;
		mExitCritical;
		return ECODE_OVERFLOW_MSGQUEUE;
	}
	if(msg_queue->type == __DYNAMIC__)
	{
		tspMsgNode msg_node = NULL;
		msg_node = (tspMsgNode)__malloc(sizeof(tsMsgNode));
		if(msg_node == NULL)
		{
			msg_queue->mutex = true;
			vFault.mallocfail_msgnode = true;
			mExitCritical;
			return ECODE_MALLOCFAIL_MSGNODE;
		}
		sSendMsg_Dynamic(msg);
	}
	else
	{
		sSendMsg_Static(msg);
	}
	msg_queue->mutex = true;
	mExitCritical;
	return ECODE_NOERR;
}

#endif

#if SYSCFG_FLAGGROUP == __ENABLED__

bool __query_grp(volatile void *p, u8 size)
{
	mEntry_Monitor;
	switch(size)
	{
		case 1:
			if(*(u8 *)p) goto LABLE;
		break;
		case 2:
			if(*(u16*)p) goto LABLE;
		break;
		case 4:
			if(*(u32*)p) goto LABLE;
		break;
	}
	mExitCritical;
	return false;
	LABLE:
	mExitCritical;
	return true;
}

bool __wait_grp(volatile void *p, u8 size, tDelay tc)
{
	u8 type;
	mEntry_Monitor;
	switch(size)
	{
		case 1:
			if(*(u8 *)p) goto LABLE_1;
			else if(!tc) goto LABLE_0;
			type = __FLAGGROUP_1__;
		break;
		case 2:
			if(*(u16*)p) goto LABLE_1;
			else if(!tc) goto LABLE_0;
			type = __FLAGGROUP_2__;
		break;
		case 4:
			if(*(u32*)p) goto LABLE_1;
			else if(!tc) goto LABLE_0;
			type = __FLAGGROUP_4__;
		break;
		default: goto LABLE_0;
	}
	vDELAY_STMR[vTASKING->TID] = tc;
	vTASKING->blocktype = ~tc ? type | __DELAY__ : type;
	vTASKING->state = __BLOCKED__;
	vTASKING->ptr = (void *)p;
	vScheduling_f = true;
	mPSV_Trigger;
	mExitCritical;
	OS_NOPxX;
	return (bool)vTASKING->blocktype;
	LABLE_0:
	mExitCritical;
	return false;
	LABLE_1:
	mExitCritical;
	return true;
}

#endif

#if SYSCFG_DYNMEMMGE == __ENABLED__

void _MALLOC_MEM_ *__umalloc(size_t size)
{
	mEntry_Monitor;
	#if MCUCFG_MCULEVEL == __FEIPAOZI__
	{
		vTASKING->ptr = __malloc(size);
		mExitCritical;
		return vTASKING->ptr;
	}
	#else
	{
		register void _MALLOC_MEM_ *r = __malloc(size);
		mExitCritical;
		return r;
	}
	#endif
}

void _MALLOC_MEM_ *__ucalloc(size_t nmemb, size_t size)
{
	mEntry_Monitor;
	#if MCUCFG_MCULEVEL == __FEIPAOZI__
	{
		vTASKING->ptr = __calloc(nmemb, size);
		mExitCritical;
		return vTASKING->ptr;
	}
	#else
	{
		register void _MALLOC_MEM_ *r = __calloc(nmemb, size);
		mExitCritical;
		return r;
	}
	#endif
}

void _MALLOC_MEM_ *__urealloc(void _MALLOC_MEM_ *p, size_t size)
{
	mEntry_Monitor;
	#if MCUCFG_MCULEVEL == __FEIPAOZI__
	{
		vTASKING->ptr = __realloc(p, size);
		mExitCritical;
		return vTASKING->ptr;
	}
	#else
	{
		register void _MALLOC_MEM_ *r = __realloc(p, size);
		mExitCritical;
		return r;
	}
	#endif
}

void __ufree(void _MALLOC_MEM_ *p)
{
	mEntry_Monitor;
	__free(p);
	mExitCritical;
}

bool __uinit_mempool(tsThrmem *p, size_t size)
{
	mEntry_Monitor;
	p->p1 = p->p2 = __malloc(size);
	if(p->p1 == NULL)
	{
		mExitCritical;
		return false;
	}
	else
	{
		p->size = size;
		mExitCritical;
		return true;
	}
}

void _MALLOC_MEM_ *__utalloc(tsThrmem *p, size_t size)
{
	mEntry_Monitor;
	if(p->p1 == NULL || (size_t)p->p2 - (size_t)p->p1 + size > p->size)
	{
		mExitCritical;
		return NULL;
	}
	else
	{
		vTASKING->ptr = p->p2;
		p->p2 = (u8 *)p->p2 + size;
		mExitCritical;
		return vTASKING->ptr;
	}
}

#endif
